#include "XComponentBackend.h"
#include "video/VideoProcessor.h"
#include "audio/AudioProcessor.h"
#include "control/touch_screen/PassThroughController.h"
#include "core/utils/AVUtils.h"
#include "core/utils/NapiUtils.h"
#include "core/utils/XComponentUtils.h"

#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN  0x0
#define LOG_TAG     "XComponentBackend"
#include <hilog/log.h>


XComponentBackend &XComponentBackend::getOrCreateInstance(const std::string_view id) {
    const auto idOwned = std::string(id);
    if (const auto it = instances.find(idOwned); it == instances.end()) {
        instances.insert({std::string(id), std::make_unique<XComponentBackend>(id)});
        OH_LOG_INFO(LOG_APP, "Created XComponent backend %{public}s", id.data());
    }
    return *instances.at(idOwned);
}

void XComponentBackend::release(const std::string_view id) {
    if (const auto erased = instances.erase(std::string(id)); erased > 0) {
        OH_LOG_INFO(LOG_APP, "Erased XComponent backend %{public}s", id.data());
    }
}

XComponentBackend::XComponentBackend(const std::string_view id) : id(id), stopFlag(false),
        videoProcessor(std::make_unique<VideoProcessor>(this)), audioProcessor(std::make_unique<AudioProcessor>(this)),
        touchHandler(std::make_unique<PassThroughController>()) {
}

XComponentBackend::~XComponentBackend() {
    OH_LOG_DEBUG(LOG_APP, "Stopping XComponentBackend %{public}s", id.c_str());
    stopFlag = true;
    audioProcessor = nullptr;
    videoProcessor = nullptr;
    OH_LOG_DEBUG(LOG_APP, "Stopped XComponentBackend %{public}s", id.c_str());
}

napi_status XComponentBackend::registerCallbacks(napi_env env, napi_value exports, std::string &xcompId) {
    OH_NativeXComponent *comp;
    {
        napi_value exportInstance = nullptr;
        NAPI_RETURN_IF_NOT_OK(napiCallResult, napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance));
        NAPI_RETURN_IF_NOT_OK(napiCallResult, napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&comp)));
    }
    {
        const auto idOpt = XComponentUtils::getId(comp);
        if (!idOpt) {
            OH_LOG_ERROR(LOG_APP, "Failed to extract id from environment XComponent");
            return napi_invalid_arg;
        }
        xcompId = *idOpt;
    }
    OH_LOG_INFO(LOG_APP, "Found XComponent %{public}s", xcompId.c_str());
    XCOMP_RETURN_IF_NOT_OK(napi_generic_failure, RegisterCallback(comp, const_cast<OH_NativeXComponent_Callback*>(&XComponentCallbacks::callbacks)));
    // TODO register mouse events
    return napi_ok;
}

